import fs from "fs-extra";
import path from "path";
import { TaskResult } from "../../common/tasks/BastTask.js";
import { toolchain } from "../../toolchain.js";
import { Mangler } from "../../tools/Mangler.js";
import { WebGLEnv } from "../WebGLEnv.js";
import { WebGLProcessJsTask } from "./WebGLPostBuildUnityTask.js";

interface IWXGameJson {
    deviceOrientation: "portrait",
    resizable?: boolean,
    iOSHighPerformance: boolean,
    "iOSHighPerformance+": boolean,
    subpackages: {
        name: string,
        root: string
    }[],
    workers: "workers"
}

export class WebGLPostBuildMiniGameTask extends WebGLProcessJsTask {
    async run(): Promise<TaskResult<void>> {
        // 使用puerts-webgl里的构建功能生成为微信环境所用的js。
        // 处理JS
        const jsRoot = path.join(WebGLEnv.ExportMiniGameRoot, WebGLEnv.MiniGameRoot);
        await this.processJSFiles(jsRoot, 'buildForMinigame');
        // 修改UnityApplication.js
        const ua = path.join(toolchain.params.workSpacePath, jsRoot, 'puerts_minigame_js_resources/System/UnityApplication.js');
        const uaContent = await fs.readFile(ua, 'utf-8');
        const newUAContent = uaContent.replace('UnityApplication.IsMiniGame = false', 'UnityApplication.IsMiniGame = true');
        await fs.writeFile(ua, newUAContent);

        const exportRoot = path.join(toolchain.params.workSpacePath, jsRoot);
        // mangle js files
        const reservedFile = path.join(toolchain.params.workSpacePath, WebGLEnv.MangleReserved);
        const cacheFile = path.join(toolchain.params.workSpacePath, WebGLEnv.MangleCache);
        // 先提取reserved字段
        const reserved = await toolchain.filterPuertsReserved.readAll(toolchain.params.workSpacePath, reservedFile);
        const mangler = new Mangler();
        const jsResrouces = path.join(exportRoot, WebGLEnv.MiniGameJsResources);
        // 由于不能达成一个bundle，故需要keep class name和properties，否则同一个类名在不同文件中可能会有不同的混淆结果
        await mangler.beginMangle(reserved, cacheFile, true, false);
        // 因不混淆properties了，所以也不能混淆json
        await mangler.mangleAll(jsResrouces, jsResrouces, '.js');
        await mangler.patchJs(jsResrouces);
        await mangler.endMangle(cacheFile);

        const gameJs = path.join(exportRoot, WebGLEnv.MiniGameJs);
        const gameJsContent = await fs.readFile(gameJs, 'utf-8');

        // 拷贝封面图片
        const rst = gameJsContent.match(/backgroundImage: '(.+)',/);
        if (rst != null) {
            const src = path.join(toolchain.params.workSpacePath, 'Assets/AssetSources/images/loadingPage/0.jpg');
            const dst = path.join(exportRoot, rst[1]);
            console.log('copy cover background image to', dst);
            await fs.copyFile(src, dst);
        }

        // 在构建出来的小游戏game.js中，添加require('puerts-runtime.js')
        if (!gameJsContent.includes('require(\'puerts-runtime.js\')')) {
            const newGameJsContent = gameJsContent + '\nrequire(\'puerts-runtime.js\');';
            await fs.writeFile(gameJs, newGameJsContent);
        }

        // 增加分包
        await this.setSubpackages(exportRoot, jsResrouces);

        // 修改配置
        if (toolchain.params.projectType == 'develop') {
            const un = path.join(exportRoot, 'unity-namespace.js');
            const unContent = await fs.readFile(un, 'utf-8');
            let newUnContent = unContent;
            if (this.cmdOption.minigameEnableDebugLog) {
                // 打开详细日志开关enableDebugLog: true查看资源日志是否有读取缓存
                newUnContent = newUnContent.replace('enableDebugLog: false', 'enableDebugLog: true');
            }
            if (this.cmdOption.minigameShowTimeLogModal) {
                // 修改hideTimeLogModal为false，显示timelog开发者可以看到小游戏目前的启动首屏时长
                newUnContent = newUnContent.replace('hideTimeLogModal: true', 'hideTimeLogModal: false');
            }
            if (this.cmdOption.minigameEnableProfileStats) {
                // 修改enableProfileStats变量打开性能面板
                newUnContent = newUnContent.replace('enableProfileStats: false', 'enableProfileStats: true');
            }
            await fs.writeFile(un, newUnContent, 'utf-8');
        }

        // 写入resVer.txt记录资源版本，以供手动上传时使用
        // 首次构建必须勾选compressTexture，否则下述copy找不到version.txt
        const assetsDir = toolchain.unity.getAssetsDir();
        await fs.copyFile(path.join(toolchain.params.uploadPath, assetsDir, 'version.txt'), path.join(toolchain.params.workSpacePath, WebGLEnv.MiniGameResVerFile));

        return { success: true, errorCode: 0, data: void 0 };
    }

    private async setSubpackages(exportRoot: string, jsResrouces: string): Promise<void> {
        const gameJson = path.join(exportRoot, 'game.json');
        const wxGameJson = await fs.readJSON(gameJson) as IWXGameJson;
        // 从minigame.js读取分包信息
        const minigameJs = path.join(jsResrouces, 'minigame.js');
        const minigameJsContent = await fs.readFile(minigameJs, 'utf-8');
        const result = minigameJsContent.match(/(?<=__subpackages = \[)[^\]]+(?=\])/g);
        if (result != null) {
            // 先清除旧的分包信息
            for (let i = wxGameJson.subpackages.length - 1; i >= 0; i--) {
                const sp = wxGameJson.subpackages[i];
                if (sp.root.startsWith(WebGLEnv.MiniGameJsResources)) {
                    wxGameJson.subpackages.splice(i, 1);
                }
            }
            const spArr = result[0].split(/,\s*/);
            let cnt = 0;
            for (const sp of spArr) {
                const subpackage = sp.substring(1, sp.length - 1);
                const spath = path.join(jsResrouces, subpackage);
                if (fs.existsSync(spath)) {
                    console.log(`add subpackage: ${subpackage}`);
                    wxGameJson.subpackages.push({ name: subpackage, root: WebGLEnv.MiniGameJsResources + '/' + subpackage });
                    // 添加分包game.js
                    const sgameJs = path.join(spath, 'game.js');
                    if (!fs.existsSync(sgameJs)) {
                        await fs.writeFile(sgameJs, `console.log('This is subpackage ${subpackage}')`, 'utf-8');
                    }
                    cnt++;
                } else {
                    console.error('subpackage not exists!', subpackage, spath);
                    process.exit(1);
                }
            }
            
            console.log(`${cnt} subpackage found~`);

            // 设置ios高性能模式
            const iOSHighPerformance = toolchain.params.channelCfg?.wx?.iOSHighPerformance;
            if (iOSHighPerformance != null) {
                wxGameJson.iOSHighPerformance = iOSHighPerformance;
            }
            const iOSHighPerformancePlus = toolchain.params.channelCfg?.wx?.["iOSHighPerformance+"];
            if (iOSHighPerformancePlus != null) {
                wxGameJson["iOSHighPerformance+"] = iOSHighPerformancePlus;
            }

            // 设置resizable
            wxGameJson.resizable = true;
            await fs.writeJSON(gameJson, wxGameJson, { spaces: 2 });
        } else {
            console.error('cannot find subpackage infomation!');
            process.exit(1);
        }
    }
}
